package ua.amsoft.brelok.manager;

import ua.amsoft.brelok.db.DatabaseOpenHelper;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;

/**
 * @author Tair Mustafaiev
 */
public class DatabaseManager {
    
    private static final String TAG = DatabaseManager.class.getName();
    
    private final DatabaseOpenHelper databaseHelper;
    
    private SQLiteDatabase database;
    
    /**
     * Constructor
     * 
     * @param context
     */
    public DatabaseManager(final Context context) {
        this.databaseHelper = new DatabaseOpenHelper(context);
    }
    
    /**
     * @return {@link DatabaseOpenHelper}
     */
    public DatabaseOpenHelper getOpenHelper() {
        return this.databaseHelper;
    }
    
    /**
     * @return an {@link SQLiteDatabase} instance
     */
    public SQLiteDatabase getSqlLiteDatabase() {
        return this.database;
    }
    
    /**
     * Opening readable/writable database. This method is wrapper for
     * {@link SQLiteOpenHelper#getWritableDatabase()}
     */
    public void open() {
        try {
            if ((this.database == null) || !this.database.isOpen()) {
                this.database = this.databaseHelper.getWritableDatabase();
                Log.i(DatabaseManager.TAG, "Database opened");
            }
        } catch (final SQLiteException e) {
            Log.e(DatabaseManager.TAG, "Database opening was not sucessful");
        }
    }
    
    /**
     * Closes readable/writable database. This method is wrapper for
     * {@link SQLiteOpenHelper#close()}
     */
    public void close() {
        if ((this.database != null) && this.database.isOpen()) {
            this.database.close();
            Log.i(DatabaseManager.TAG, "Database closed");
        }
    }
    
    /**
     * Inserts row to specified table in the database
     * 
     * @param table - database table
     * @param nullColumnHack - column hack
     * @param values - {@link ContentValues} values to be inserted
     * @return inserted rod ID
     */
    public long insert(final String table, final String nullColumnHack, final ContentValues values) {
        checkIsDatabaseReady();
        return this.database.insert(table, nullColumnHack, values);
    }
    
    /**
     * Executes update statement
     * 
     * @param table - database table name
     * @param values - {@link ContentValues} values to be inserted
     * @param whereClause - where clauses
     * @param whereArgs - where args
     */
    public void executeUpdate(final String table, final ContentValues values,
            final String whereClause, final String[] whereArgs) {
        checkIsDatabaseReady();
        this.database.update(table, values, whereClause, whereArgs);
    }
    
    /**
     * Selects a {@link Cursor} object contained database rows
     * 
     * @param sql - SQL query
     * @param selectionArgs - query arguments
     * @return {@link Cursor} rows from database
     */
    public Cursor select(final String sql, final String[] selectionArgs) {
        checkIsDatabaseReady();
        return this.database.rawQuery(sql, selectionArgs);
    }
    
    /**
     * Selects ordered {@link Cursor}
     * 
     * @param table - table name
     * @param columns - columns
     * @param selection - what be selected
     * @param selectionArgs - query selection arguments
     * @param groupBy - group by column
     * @param having - having statement
     * @param orderBy - order by statement
     * @return {@link Cursor} rows from database
     */
    public Cursor selectOrderBy(final String table, final String[] columns, final String selection,
            final String[] selectionArgs, final String groupBy, final String having,
            final String orderBy) {
        return this.database.query(table, columns, selection, selectionArgs, groupBy, having,
                orderBy);
    }
    
    /**
     * Selects rows with distinct and limit
     * 
     * @param distinct is distinct needed
     * @param table - table name
     * @param columns - columns
     * @param selection - selection
     * @param selectionArgs - selection arguments
     * @param groupBy - group by column
     * @param having - having statement
     * @param orderBy - order by statement
     * @param limit - limit
     * @return {@link Cursor} rows from database
     */
    public Cursor selectDistinctLimit(final boolean distinct, final String table,
            final String[] columns, final String selection, final String[] selectionArgs,
            final String groupBy, final String having, final String orderBy, final String limit) {
        return this.database.query(distinct, table, columns, selection, selectionArgs, groupBy,
                having, orderBy, limit);
    }
    
    /**
     * Deletes rows from database
     * 
     * @param table - database table name
     * @param whereClause - where clauses
     * @param whereArgs - where args
     * @return count of deleted rows
     */
    public int delete(final String table, final String whereClause, final String[] whereArgs) {
        return this.database.delete(table, whereClause, whereArgs);
    }
    
    /**
     * Check is the database object is ready for reading and writing
     */
    private void checkIsDatabaseReady() {
        if (this.database == null) {
            throw new SQLiteException("Database instance is null");
        } else if (!this.database.isOpen()) {
            throw new SQLiteException("Database is not opened");
        } else if (this.database.isReadOnly()) {
            throw new SQLiteException("Database is read only");
        }
    }
    
}
